//! 模拟交易所
//!
//! 做市机构/撮合引擎/结算引擎的集成中心,
//! 多线程处理各职能实例

use crate::clearing::{ClearingCenter, ClearingError, ClearingTrait};
use crate::engine::{MatchEngine, MatchEngineTrait};
use anyhow::Result;
use eztrade_dto::{events::SubscribeEvent, order::Order, tick::TickData, user::Portfolio};
use std::sync::Arc;
use tokio::signal;
use tokio::sync::broadcast;
use tokio::time::{Duration, interval};

/// 交易所聚合器
pub struct Exchange {
    pub match_engine: MatchEngine,
    pub clearing_center: ClearingCenter,
    shutdown_sender: broadcast::Sender<()>,
}

pub trait ExchangeTrait {
    /// 启动交易所职能
    fn run(self: Arc<Self>, tick_us: u64) -> impl std::future::Future<Output = ()> + Send;
    /// 停止交易所
    fn stop(&self) -> Result<()>;
    /// 添加用户(返回账号默认资产)
    fn add_account(&self, client_id: u64) -> Result<Portfolio>;
    /// 获取用户数据
    fn get_portfolio(&self, client_id: u64) -> Result<Portfolio>;
    /// 订阅事件
    fn client_subscribe(&self, client_id: u64, event: Arc<SubscribeEvent>) -> Result<()>;
    /// Tick数据(Orderbook)
    fn tick_data(&self, symbol: &str) -> Result<TickData>;
    /// Order操作
    fn place_order(&self, order: Order, client_id: u64) -> Result<Order>;
    fn cancel_order(&self, order_id: u64, client_id: u64) -> Result<()>;
    fn query_order(&self, order_id: u64, client_id: u64) -> Option<Order>;
}

impl Default for Exchange {
    fn default() -> Self {
        let (sender, _receiver) = broadcast::channel(1);
        Self {
            match_engine: MatchEngine::new(),
            clearing_center: ClearingCenter::default(),
            shutdown_sender: sender,
        }
    }
}

impl Exchange {
    /// 创建新的交易所实例
    pub fn new() -> Arc<Self> {
        Arc::new(Self::default())
    }

    // 提供与 MatchEngine 相同的方法签名，内部转发
    pub fn update_timestamp(&self, timestamp_us: u64) {
        self.clearing_center.update_timestamp(timestamp_us);
        self.match_engine.update_timestamp(timestamp_us);
    }

    pub fn match_all_symbols(&self) {
        self.match_engine.match_all_symbols();
    }
}

impl ExchangeTrait for Exchange {
    /// 启动交易所职能
    #[tracing::instrument(skip_all, parent = None, name = "exchange_run")]
    async fn run(self: Arc<Self>, tick_us: u64) {
        // 创建关闭信号接收器
        let mut shutdown_receiver = self.shutdown_sender.subscribe();

        let mut interval = interval(Duration::from_micros(tick_us));
        loop {
            tokio::select! {
                _ = interval.tick() => {
                    // phase 0: 更新当前时间戳(外部)
                    // phase 1: 由Exchange接收数据并维护OrderVecDeque和Location？
                    // phase 1-1: 收集此刻的交易者指令队列(外部), 第一时间返回单号(后续检查订单状态), 同时放入待结果队列，清算中心待校验队列放入Arc
                    // phase 1-2: 做市商根据需求生成订单(可选), 放入待结果队列, 清算中心待校验队列获取Arc
                    // Order生命周期开始(在待处理队列当中)
                    // phase 2-1: 将订单队列通过清算中心放入订单簿匹配队列       place_order
                    // phase 2-2: 从清除指令校验合法性并放入订单簿执行remove队列 cancel_order
                    // 将校验通过的订单移动到撮合引擎
                    self.clearing_center
                        .place_to_match_engine(&self.match_engine);
                    // phase 3-1: 根据指令队列和交易者信息, 进行合法性检查, 包括资金检查, 持仓检查等
                    // phase 3-2: 将合法的订单放入撮合引擎的订单簿, 不合法的订单返回错误信息（待处理队列清理返回一波Order）
                    // phase 4-1: 执行撮合引擎的撮合逻辑并生成Trade和DoneOrder队列
                    // phase 4-1: 更新市场数据(需要逐单校验, 此时将remove队列一并执行, 清理掉的也放入DoneOrder队列中)
                    // 在交易所层面手动推进一次撮合周期
                    self.match_engine.place_order_queue_into_book();
                    self.match_engine.update_orderbooks();
                    self.match_engine.match_all_symbols();
                    // phase 5: Drain Trade和DoneOrder, 根据撮合结果更新用户的资金和持仓信息, 将记录持久化, 清空已完成的队列（待处理队列清理返回一波Order）
                    self.clearing_center
                        .process_trades(&self.match_engine);
                    // clearing/matchmake 这两个职能模块之间通过异步队列通信, 模块内聚依赖无锁并行, 职能模块间并发执行
                    // marketmaker 置于沙盒中和client同层发送指令
                }
                _ = shutdown_receiver.recv() => {
                    tracing::info!("收到停止信号，交易所正在关闭...");
                    break;
                }

                _ = signal::ctrl_c() => {
                    tracing::warn!("收到 Ctrl+C 信号，开始优雅关闭");
                    break;
                }
            }
        }
        tracing::info!("交易所已停止运行");
    }

    fn stop(&self) -> Result<()> {
        match self.shutdown_sender.send(()) {
            Ok(_) => {
                tracing::info!("停止信号已发送");
                Ok(())
            }
            Err(_) => {
                // 如果没有接收器在监听，这通常意味着交易所已经停止或从未启动
                tracing::warn!("没有活跃的接收器，交易所可能已经停止");
                Ok(())
            }
        }
    }

    fn add_account(&self, _client_id: u64) -> Result<Portfolio> {
        Ok(self.clearing_center.get_or_create_portfolio(_client_id))
    }

    fn tick_data(&self, symbol: &str) -> Result<TickData> {
        let res_tick_data = self.match_engine.tick_data.get(symbol);
        match res_tick_data {
            Some(tick_data) => Ok(tick_data.clone()),
            None => Err(anyhow::anyhow!("Tick data not found")),
        }
    }

    fn place_order(&self, order: Order, client_id: u64) -> Result<Order> {
        match self.clearing_center.place_order_vertify(order, client_id) {
            Ok(order) => Ok(order),
            Err(ClearingError::UserNotFound) => Err(anyhow::anyhow!("User not found")),
            // TODO: 后面再精细化处理
            Err(err) => Err(anyhow::anyhow!(format!("Failed to place order: {:?}", err))),
        }
    }

    fn cancel_order(&self, order_id: u64, client_id: u64) -> Result<()> {
        log::trace!("撤销订单指令!");
        match self
            .clearing_center
            .cancel_order_vertify(order_id, client_id)
        {
            Ok(_) => Ok(()),
            Err(e) => Err(anyhow::anyhow!(format!("Failed to cancel order: {:?}", e))),
        }
    }

    fn get_portfolio(&self, _client_id: u64) -> Result<Portfolio> {
        Ok(self.clearing_center.get_or_create_portfolio(_client_id))
    }

    fn query_order(&self, order_id: u64, client_id: u64) -> Option<Order> {
        self.clearing_center.query_order(order_id, client_id)
    }

    fn client_subscribe(&self, client_id: u64, event: Arc<SubscribeEvent>) -> Result<()> {
        match event.dtype {
            eztrade_dto::events::DataType::OrderDone => {
                // 这些事件类型需要用户ID
                self.clearing_center
                    .client_subscribe_event(client_id, event);
            }
            _ => {
                // 其他事件类型暂无实现
            }
        }
        Ok(())
    }
}
